package com.xzy.learn.spring.bean.initialization;

import com.xzy.learn.spring.bean.initialization.bean.StudentA;
import com.xzy.learn.spring.bean.initialization.bean.StudentB;
import com.xzy.learn.spring.bean.initialization.bean.StudentC;
import com.xzy.learn.spring.bean.initialization.bean.StudentD;
import org.springframework.beans.factory.support.AbstractBeanDefinition;
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.annotation.Bean;
import org.springframework.context.support.ClassPathXmlApplicationContext;

/**
 * 初始化 Bean 的方式
 *
 * @author xzy.xiao
 * @date 2022/6/1  17:01
 */
public class InitializationDeanDemo {

    public static void main(String[] args) {
        //initializationByPostConstructAnnotation();
        //initializationByInitializingBeanInterface();
        //initializationByInitMethod();
        test();
    }

    /**
     * 初始化方式：通过 @PostConstruct 标注的方法
     */
    public static void initializationByPostConstructAnnotation() {
        AnnotationConfigApplicationContext annotationConfigApplicationContext = new AnnotationConfigApplicationContext();
        annotationConfigApplicationContext.register(StudentA.class);
        annotationConfigApplicationContext.refresh();

        StudentA bean = annotationConfigApplicationContext.getBean(StudentA.class);
        System.out.println(bean);

        annotationConfigApplicationContext.close();
    }

    /**
     * 初始化方式：通过实现 InitializingBean 接口的 afterPropertiesSet() 方法
     */
    public static void initializationByInitializingBeanInterface() {
        AnnotationConfigApplicationContext annotationConfigApplicationContext = new AnnotationConfigApplicationContext();
        annotationConfigApplicationContext.register(StudentB.class);
        annotationConfigApplicationContext.refresh();

        StudentB bean = annotationConfigApplicationContext.getBean(StudentB.class);
        System.out.println(bean);

        annotationConfigApplicationContext.close();
    }

    /**
     * 初始化方式：通过自定义的初始化方法
     */
    public static void initializationByInitMethod() {
        //setInitMethodByBeanDefinition();
        setInitMethodByBeanConfig();
    }

    /**
     * 通过 BeanDefinition 设置初始化方法
     */
    private static void setInitMethodByBeanDefinition() {
        BeanDefinitionBuilder beanDefinitionBuilder = BeanDefinitionBuilder.genericBeanDefinition(StudentC.class);
        beanDefinitionBuilder.setInitMethodName("myInitMethod");

        AnnotationConfigApplicationContext annotationConfigApplicationContext = new AnnotationConfigApplicationContext();
        annotationConfigApplicationContext.registerBeanDefinition("studentC", beanDefinitionBuilder.getBeanDefinition());
        annotationConfigApplicationContext.refresh();

        StudentC bean = annotationConfigApplicationContext.getBean(StudentC.class);
        System.out.println(bean);

        annotationConfigApplicationContext.close();
    }

    /**
     * 通过 Bean 配置设置初始化方法：{@link Bean#initMethod()}
     */
    private static void setInitMethodByBeanConfig() {
        ClassPathXmlApplicationContext classPathXmlApplicationContext = new ClassPathXmlApplicationContext("classpath:/META-INF/bean-initialization.xml");

        StudentC bean = classPathXmlApplicationContext.getBean(StudentC.class);
        System.out.println(bean);

        classPathXmlApplicationContext.close();

        /*
         * 配置 Bean 的方式：
         * 1、<bean init-method=""/>
         * 2、@Bean(initMethod="")
         */
    }

    /**
     * 测试：如果同时设置了多种初始化方式，它们的执行顺序是怎样的？
     */
    private static void test() {
        BeanDefinitionBuilder beanDefinitionBuilder = BeanDefinitionBuilder.genericBeanDefinition(StudentD.class);
        beanDefinitionBuilder.setInitMethodName("myInitMethod");
        AbstractBeanDefinition beanDefinition = beanDefinitionBuilder.getBeanDefinition();

        AnnotationConfigApplicationContext annotationConfigApplicationContext = new AnnotationConfigApplicationContext();
        annotationConfigApplicationContext.registerBeanDefinition("studentD", beanDefinition);
        annotationConfigApplicationContext.refresh();

        StudentD bean = annotationConfigApplicationContext.getBean(StudentD.class);
        System.out.println(bean);

        annotationConfigApplicationContext.close();
    }
}
